<?php
declare(strict_types=1);

namespace Reven\HyperfRedisBasics\lock;


use Hyperf\Redis\Redis;
use Reven\HyperfRedisBasics\RedisTrait;

class Lock
{
    protected string $redisKey;

    protected int $ttl;

    protected bool $lock;

    use RedisTrait;

    /**
     * Lock constructor.
     * @param string $redisKey
     * @param int $ttl 有效期单位毫秒
     * @param bool $lock 是否为锁 如果不是 仅判断有效时间内key是否存在
     */
    public function __construct(string $redisKey,int $ttl=3000,bool $lock=false)
    {
        $this->lock=$lock;
        $this->ttl=$ttl;
        $this->redisKey=$redisKey;
        $this->init();

    }

    public function getLock():bool {
        if (!$this->lock){
            $re=$this->redis->exists($this->redisKey);
            if ($re){
                return false;
            }
            $this->redis->psetex($this->redisKey,$this->ttl,1);

            return true;
        }else{
            $re=$this->redis->setnx($this->redisKey,1);
            if (!$re){
                return false;
            }
            $this->redis->pExpire($this->redisKey,$this->ttl);
            return true;
        }
    }

    /**
     * 补偿死锁的情况,(setnx 设置成功 pExpire 设置失败 或系统出现问题是，需要手动设置锁的有效期)
     * @param float $ttlMultiple
     * @return bool
     */
    public function makeDieLock(float $ttlMultiple=1.5){
        $re=true;
        if ($this->lock){
            // 避免死锁了应用不过期，自动1.5倍有效期
            $re= $this->redis->pExpire($this->redisKey,$this->ttl*$ttlMultiple);
        }
        return $re;
    }

    /**
     * 解锁
     * @param bool $makeDieLock
     * @return bool
     */
    public function unlock(bool $makeDieLock=false):bool {
        if ($makeDieLock&&$this->lock){
            $this->makeDieLock();
        }
        return !!$this->redis->del($this->redisKey);
    }

}